#import copy
import PLY.lex as lex

tokens = (
'tkFloat',
'tkIdentifier',
'tkInteger',
'tkAssign',
'tkComma',
'tkColon',
'tkDotDot',
'tkPoint',
'tkRparen',
'tkLparen',
'tkSemiColon',
'tkLbrac',
'tkRbrac',
'tkArray',
'tkBegin',
'tkCase',
'tkConst',
'tkDo',
'tkElse',
'tkEnd',
'tkFor',
'tkFunction',
'tkIf',
'tkNot',
'tkOf',
'tkProcedure',
'tkProgram',
'tkRecord',
'tkRepeat',
'tkString',
'tkThen',
'tkTo',
'tkType',
'tkUntil',
'tkUses',
'tkVar',
'tkWhile',
'tkMinus',
'tkPlus',
'tkOr',
'tkXor',
'tkAnd',
'tkDiv',
'tkMod',
'tkEqual',
'tkGreater',
'tkGreaterEqual',
'tkLower',
'tkLowerEqual',
'tkNotEqual',
'tkByte',
'tkWordV',
'tkBoolean',
'tkReal',
'tkSingleV',
'tkDoubleV',
'tkRealV',
'tkIntegerV',
'tkFloatV',
'tkStringV',
'tkBooleanV',
'tkByteV',
'tkLongIntV',
'tkCharV'
)

literals = ['=','(',')']

## Diccionario

reserved = {
'ARRAY':'tkArray',
'BEGIN':'tkBegin',
'CASE':'tkCase',
'CONST':'tkConst',
'DO':'tkDo',
'ELSE':'tkElse',
'END':'tkEnd',
'EXPORTS':'tkExports',
'FOR':'tkFor',
'FUNCTION':'tkFunction',
'IF':'tkIf',
'NOT':'tkNot',
'OF':'tkOf',
'PROCEDURE':'tkProcedure',
'PROGRAM':'tkProgram',
'RECORD':'tkRecord',
'REPEAT':'tkRepeat',
'THEN':'tkThen',
'TO':'tkTo',
'TYPE':'tkType',
'UNTIL':'tkUntil',
'USES':'tkUses',
'VAR':'tkVar',
'WHILE':'tkWhile',
'OR':'tkOr',
'XOR':'tkXor',
'AND':'tkAnd',
'DIV':'tkDiv',
'MOD':'tkMod',
'EXPORT':'tkExport',
'TRUE': 'tkBoolean',
'FALSE': 'tkBoolean',
'REAL' : 'tkRealV',
'INTEGER' : 'tkIntegerV',
'FLOAT' : 'tkFloatV',
'STRING' : 'tkStringV',
'BOOLEAN' : 'tkBooleanV',
'BYTE' : 'tkByteV',
'LONGINT' : 'tkLongIntV',
'DOUBLE' : 'tkDoubleV',
'WORD' : 'tkWordV',
'SINGLE' : 'tkSingleV',
'CHAR' : 'tkCharV'
}

# Simples
t_tkAssign = ':='
t_tkColon = ':'
t_tkComma = ','
t_tkEqual = '='
t_tkNotEqual = '<>'
t_tkGreaterEqual = '>='
t_tkGreater = '>'
t_tkLowerEqual = '<='
t_tkLower = '<'
t_tkSemiColon = ';'
t_tkLbrac = "\["   ## Ver si realmente es este
t_tkLparen= "\("
t_tkRparen = "\)"
t_tkRbrac = "\]"  ## Ver si realmente es este
t_tkPoint = '\.'
t_tkDotDot = '\.\.'
#Tipos de datos mas normales numericos
t_tkByte = r'\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b'
t_tkInteger = r'[\+-]?\d+'
t_tkReal= r'((\d*\.\d+)(E[\+-]?\d+)?|([1-9]\d*E[\+-]?\d+))'
#Los 4 operadores matematicos
t_tkMinus = '\-'
t_tkPlus = '\+'
t_tkMod = '\*'
t_tkDiv = '\/'

def t_tkIdentifier(t):
    r'[a-zA-Z_][a-zA-Z_0-9]*'
    valorprimero = t.value
    valorsegundo = valorprimero.upper() # pasa a mayuscula
    valor = reserved.get(valorsegundo,'ID')    # Check for reserved words
    if not(valor != 'ID'): t.value = valorsegundo.lower()
    else:
        t.value = valorsegundo.lower()
        t.type = valor
    return t

def t_tkString(t):
    r'\'([^\\\n]|(\\.))*?\''
    return t

def find_column(input,token):
    i = token.lexpos
    t = 0
    k = 0   ##inicializo k en 0
    while i > 0:
        if input[i] == '\n': break
        if input[i] == '\t': ##controlar si el caracter es un tab (expresion regular '\t')
            k +=1            ##si es asi tengo un contador para la cantidad de tabs
        i -=1                ##resta la cantidad de caracteres (no se considera tab como 8 caracteres, sino como uno solo) desde la columna relativa (la que maneja python) del token hasta el principio de la linea del token
    if (token.lineno == 1):
        k +=1
        t = 0
    else:
        t = 1
    column = ((((token.lexpos - i) + (k*8)) - k) - t)      ##formula que calcula las columnas ok
    return column

# Una cadena que contiene caracteres que se ignoran (espacios y tabs)
t_ignore = ' \t'

# Define una regla asi podemos rastrear el numero de linea
def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

# Regla de manejo de errores
def t_error(t):

    print "Token o caracter no permitido '%s' " % t.value[0] + "en linea: '%s'" % t.lineno + ", columna: '%s'" % find_column(code,t)
    t.lexer.skip(1)

def t_comentario(t):
    r'((\{([^\\\n]|(\\.))*?\})|(\(\*([^\\\n]|(\\.))*?\*\)))'
    return None

lex.lex()
if __name__ == '__main__':
    print("---------Inicio del tokenizer--------------")
    source_filename = 'Codigos_Fuentes\Codigo.pas'
    source = open(source_filename, 'r')
    code = source.read()
    source.close()

    # Pruebalo
    # Darle al lexer alguna entrada
    lex.input(code)

    # Tokenize trae cada token y lo imprime, hasta que no haya
    while 1:
        try:
            tok = lex.token()
        except:
            print "Corrija el error lexico para continuar"
            break

        if not tok:
            break      # No hay mas entrada

        print tok   #Imprime el token que ha sido pasado...
